1   /*
2    * Copyright (C) 2005 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.collect.ImmutableMap;
21  import com.google.common.collect.Maps;
22  import com.google.common.testing.EqualsTester;
23  
24  import junit.framework.TestCase;
25  
26  import java.io.Serializable;
27  import java.util.Map;
28  
29  /**
30   * Tests for {@link Functions}.
31   *
32   * @author Mike Bostock
33   * @author Vlad Patryshev
34   */
35  @GwtCompatible(emulated = true)
36  public class FunctionsTest extends TestCase {
37  
38    public void testIdentity_same() {
39      Function<String, String> identity = Functions.identity();
40      assertNull(identity.apply(null));
41      assertSame("foo", identity.apply("foo"));
42    }
43  
44    public void testIdentity_notSame() {
45      Function<Long, Long> identity = Functions.identity();
46      assertNotSame(new Long(135135L), identity.apply(new Long(135135L)));
47    }
48  
49    public void testToStringFunction_apply() {
50      assertEquals("3", Functions.toStringFunction().apply(3));
51      assertEquals("hiya", Functions.toStringFunction().apply("hiya"));
52      assertEquals("I'm a string",
53          Functions.toStringFunction().apply(
54              new Object() {
55                @Override public String toString() {
56                  return "I'm a string";
57                }
58              }));
59      try {
60        Functions.toStringFunction().apply(null);
61        fail("expected NullPointerException");
62      } catch (NullPointerException e) {
63        // expected
64      }
65    }
66  
67    public void testForMapWithoutDefault() {
68      Map<String, Integer> map = Maps.newHashMap();
69      map.put("One", 1);
70      map.put("Three", 3);
71      map.put("Null", null);
72      Function<String, Integer> function = Functions.forMap(map);
73  
74      assertEquals(1, function.apply("One").intValue());
75      assertEquals(3, function.apply("Three").intValue());
76      assertNull(function.apply("Null"));
77  
78      try {
79        function.apply("Two");
80        fail();
81      } catch (IllegalArgumentException expected) {
82      }
83  
84      new EqualsTester()
85          .addEqualityGroup(function, Functions.forMap(map))
86          .addEqualityGroup(Functions.forMap(map, 42))
87          .testEquals();
88    }
89  
90    public void testForMapWithDefault() {
91      Map<String, Integer> map = Maps.newHashMap();
92      map.put("One", 1);
93      map.put("Three", 3);
94      map.put("Null", null);
95      Function<String, Integer> function = Functions.forMap(map, 42);
96  
97      assertEquals(1, function.apply("One").intValue());
98      assertEquals(42, function.apply("Two").intValue());
99      assertEquals(3, function.apply("Three").intValue());
100     assertNull(function.apply("Null"));
101 
102     new EqualsTester()
103         .addEqualityGroup(function, Functions.forMap(map, 42))
104         .addEqualityGroup(Functions.forMap(map))
105         .addEqualityGroup(Functions.forMap(map, null))
106         .addEqualityGroup(Functions.forMap(map, 43))
107         .testEquals();
108   }
109 
110   public void testForMapWithDefault_null() {
111     ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
112     Function<String, Integer> function = Functions.forMap(map, null);
113 
114     assertEquals((Integer) 1, function.apply("One"));
115     assertNull(function.apply("Two"));
116 
117     // check basic sanity of equals and hashCode
118     new EqualsTester()
119         .addEqualityGroup(function)
120         .addEqualityGroup(Functions.forMap(map, 1))
121         .testEquals();
122   }
123 
124   public void testForMapWildCardWithDefault() {
125     Map<String, Integer> map = Maps.newHashMap();
126     map.put("One", 1);
127     map.put("Three", 3);
128     Number number = Double.valueOf(42);
129     Function<String, Number> function = Functions.forMap(map, number);
130 
131     assertEquals(1, function.apply("One").intValue());
132     assertEquals(number, function.apply("Two"));
133     assertEquals(3L, function.apply("Three").longValue());
134   }
135 
136   public void testComposition() {
137     Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
138     mJapaneseToInteger.put("Ichi", 1);
139     mJapaneseToInteger.put("Ni", 2);
140     mJapaneseToInteger.put("San", 3);
141     Function<String, Integer> japaneseToInteger =
142         Functions.forMap(mJapaneseToInteger);
143 
144     Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
145     mIntegerToSpanish.put(1, "Uno");
146     mIntegerToSpanish.put(3, "Tres");
147     mIntegerToSpanish.put(4, "Cuatro");
148     Function<Integer, String> integerToSpanish =
149         Functions.forMap(mIntegerToSpanish);
150 
151     Function<String, String> japaneseToSpanish =
152         Functions.compose(integerToSpanish, japaneseToInteger);
153 
154     assertEquals("Uno", japaneseToSpanish.apply("Ichi"));
155     try {
156       japaneseToSpanish.apply("Ni");
157       fail();
158     } catch (IllegalArgumentException e) {
159     }
160     assertEquals("Tres", japaneseToSpanish.apply("San"));
161     try {
162       japaneseToSpanish.apply("Shi");
163       fail();
164     } catch (IllegalArgumentException e) {
165     }
166 
167     new EqualsTester()
168         .addEqualityGroup(
169             japaneseToSpanish,
170             Functions.compose(integerToSpanish, japaneseToInteger))
171         .addEqualityGroup(japaneseToInteger)
172         .addEqualityGroup(integerToSpanish)
173         .addEqualityGroup(
174             Functions.compose(japaneseToInteger, integerToSpanish))
175         .testEquals();
176   }
177 
178   public void testCompositionWildcard() {
179     Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap();
180     Function<String, Integer> japaneseToInteger =
181         Functions.forMap(mapJapaneseToInteger);
182 
183     Function<Object, String> numberToSpanish = Functions.constant("Yo no se");
184 
185     Function<String, String> japaneseToSpanish =
186         Functions.compose(numberToSpanish, japaneseToInteger);
187   }
188 
189   private static class HashCodeFunction implements Function<Object, Integer> {
190     @Override
191     public Integer apply(Object o) {
192       return (o == null) ? 0 : o.hashCode();
193     }
194   }
195 
196   public void testComposeOfFunctionsIsAssociative() {
197     Map<Float, String> m = ImmutableMap.of(
198         4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
199     Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE);
200     Function<? super String, Integer> g = new HashCodeFunction();
201     Function<Float, String> f = Functions.forMap(m, "F");
202 
203     Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f);
204     Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f));
205 
206     // Might be nice (eventually) to have:
207     //     assertEquals(c1, c2);
208 
209     // But for now, settle for this:
210     assertEquals(c1.hashCode(), c2.hashCode());
211 
212     assertEquals(c1.apply(1.0f), c2.apply(1.0f));
213     assertEquals(c1.apply(5.0f), c2.apply(5.0f));
214   }
215 
216   public void testComposeOfPredicateAndFunctionIsAssociative() {
217     Map<Float, String> m = ImmutableMap.of(
218         4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
219     Predicate<? super Integer> h = Predicates.equalTo(42);
220     Function<? super String, Integer> g = new HashCodeFunction();
221     Function<Float, String> f = Functions.forMap(m, "F");
222 
223     Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f);
224     Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f));
225 
226     // Might be nice (eventually) to have:
227     //     assertEquals(p1, p2);
228 
229     // But for now, settle for this:
230     assertEquals(p1.hashCode(), p2.hashCode());
231 
232     assertEquals(p1.apply(1.0f), p2.apply(1.0f));
233     assertEquals(p1.apply(5.0f), p2.apply(5.0f));
234   }
235 
236   public void testForPredicate() {
237     Function<Object, Boolean> alwaysTrue =
238         Functions.forPredicate(Predicates.alwaysTrue());
239     Function<Object, Boolean> alwaysFalse =
240         Functions.forPredicate(Predicates.alwaysFalse());
241 
242     assertTrue(alwaysTrue.apply(0));
243     assertFalse(alwaysFalse.apply(0));
244 
245     new EqualsTester()
246         .addEqualityGroup(
247             alwaysTrue, Functions.forPredicate(Predicates.alwaysTrue()))
248         .addEqualityGroup(alwaysFalse)
249         .addEqualityGroup(Functions.identity())
250         .testEquals();
251   }
252 
253   public void testConstant() {
254     Function<Object, Object> f = Functions.<Object>constant("correct");
255     assertEquals("correct", f.apply(new Object()));
256     assertEquals("correct", f.apply(null));
257 
258     Function<Object, String> g = Functions.constant(null);
259     assertEquals(null, g.apply(2));
260     assertEquals(null, g.apply(null));
261 
262     new EqualsTester()
263         .addEqualityGroup(f, Functions.constant("correct"))
264         .addEqualityGroup(Functions.constant("incorrect"))
265         .addEqualityGroup(Functions.toStringFunction())
266         .addEqualityGroup(g)
267         .testEquals();
268 
269     new EqualsTester()
270         .addEqualityGroup(g, Functions.constant(null))
271         .addEqualityGroup(Functions.constant("incorrect"))
272         .addEqualityGroup(Functions.toStringFunction())
273         .addEqualityGroup(f)
274         .testEquals();
275   }
276 
277   private static class CountingSupplier
278       implements Supplier<Integer>, Serializable {
279 
280     private static final long serialVersionUID = 0;
281 
282     private int value;
283 
284     @Override
285     public Integer get() {
286       return ++value;
287     }
288 
289     @Override
290     public boolean equals(Object obj) {
291       if (obj instanceof CountingSupplier) {
292         return this.value == ((CountingSupplier) obj).value;
293       }
294       return false;
295     }
296 
297     @Override
298     public int hashCode() {
299       return value;
300     }
301   }
302 
303   public void testForSupplier() {
304     Supplier<Integer> supplier = new CountingSupplier();
305     Function<Object, Integer> function = Functions.forSupplier(supplier);
306 
307     assertEquals(1, (int) function.apply(null));
308     assertEquals(2, (int) function.apply("foo"));
309 
310     new EqualsTester()
311         .addEqualityGroup(function, Functions.forSupplier(supplier))
312         .addEqualityGroup(Functions.forSupplier(new CountingSupplier()))
313         .addEqualityGroup(Functions.forSupplier(Suppliers.ofInstance(12)))
314         .addEqualityGroup(Functions.toStringFunction())
315         .testEquals();
316   }
317 
318 }
319